#include <string>
#include <map>
#include <vector>
#include <iostream>
#include <sstream>

#ifndef WINHEX_TEMPLATE_H
#define WINHEX_TEMPLATE_H

#define WINHEX_TEMPLATE_DIR  "./tpl/"
#define WINHEX_TEMPLATE_LENGTH  512


////模板注释
typedef struct {
    int color;   //颜色
    bool isB;   //是否加粗    
    string name; //内容
    int len;         //长度单位字节
//    string des;     //中文描述
} WINHEX_TEMPLATENOTE;

vector<string>  winhex_template_files;

//属性模板 0x10="000001111000002220000",  多个字节 0表示没有颜色   其他表示字节所在位置所使用的颜色值
map<string,char*> winhexTemplateAttr;
map<string,map<int,WINHEX_TEMPLATENOTE> > winhexTemplateNodeName;
//模板注释以 行为单位的的一个缓冲  
vector<WINHEX_TEMPLATENOTE> winhexTemplateNotes;
string Template_Now;

int WinhexTemplate_init_parse(string key){
    int rt=0;
    if(key.compare("template")==0 || key.compare("description")==0) {
        rt=0;
    }else if(key.compare("section")==0) {
        rt=0;
    }else if(key.find("requires")==0){
         rt=0;
    }else if(key.find("hex ")!=string::npos){
        int i=key.find("hex ")+4;
        rt=atoi(key.substr(i).c_str());
    }else if(key.find("uint")!=string::npos || key.find("UInt")!=string::npos){
        rt=atoi(key.substr(4).c_str())/8;
    }else if(key.find("char[")!=string::npos){
        rt=atoi(key.substr(5,key.length()-2).c_str());
    }else if(key.find("int")!=string::npos || key.find("Int")!=string::npos){
        rt=atoi(key.substr(3,key.length()-2).c_str())/8;
    }else if(key.compare("FileTime")==0 ||key.compare("UNIXDateTime")==0 ||key.compare("DOSDateTime")==0 ||key.compare("AppleDateTime")==0 ){
        rt=8;
    }
    
    return rt;
}

//初始化模板
void WinhexTemplate_init(string file){
//    cout << file << endl;
    Template_Now=file;
    if(winhexTemplateAttr.count(file)>0) return;
    vector<string> rows=filea(WINHEX_TEMPLATE_DIR+file);
    map<string,string> data;    
    int nowColor=0,index=0,jumpLen=-1; 
    char *p = (char *) malloc(TEMPLATE_LENGTH);
    
    memset(p,0,TEMPLATE_LENGTH);
    winhexTemplateAttr[file]=p;
    
    foreach(rows,line){
        if(line->find('"')==string::npos ){
            data[*line]="";
            
            if(line->find("goto 0x") != string::npos) {
                vector<string> a=split(*line);
                int add = htoi(a.at(2).c_str());
                p=winhexTemplateAttr[file]+add;
//                cout <<"goto:"<<a.at(2) << endl;
            }
            continue;
        }else if(line->find("{")!=string::npos){
            jumpLen=0;
        }else if(line->find("}")!=string::npos && line->find("[")!=string::npos){
            *line=trim(*line);
            int i=line->find("[");
            int rcount=atoi(line->substr(i,line->length()-2).c_str());
            p+=jumpLen*rcount;
            jumpLen=-1;
        }else if(line->find("goto") != string::npos) {    //goto的数据是根据当前数据决定的 需要结合实际数据 单纯的模板初始化是无法处理的 
            break;
//            vector<string> a=split(*line);
//            string lable=a.at(2);
//            foreach(winhexTemplateNodeName[file],it){
//                WINHEX_TEMPLATENOTE node=it->second;
//                index= it->first;
//                if(lable.find(node.name) != string::npos) {
//                      char num[100];
//                      memset(num, 0, sizeof (num));
//                      memcpy(num, winhexTemplateAttr[file]+index, node.len);
//                    long n=*((long *) &num);
//                    p=winhexTemplateAttr[file]+n;
//                    break;
//                }
//            }
        }
        
        int i=line->find('"');
        string key=line->substr(0,i);
        string val=line->substr(i+1,line->find_last_of ('"')-i);
        key=trim(key);
        int len=WinhexTemplate_init_parse(key);
        data[key]=val;
        if(len==0) continue;
        if(jumpLen!=-1) jumpLen+=len;
        
        nowColor=++nowColor%8; if(nowColor==0) nowColor=1;
        for(i=0;i<len;i++)  *(p+i)=nowColor;
        index=p-winhexTemplateAttr[file];
        winhexTemplateNodeName[file][index]=(WINHEX_TEMPLATENOTE){nowColor,false,val,len};
        p+=len;
    }
    
    int len2=p-winhexTemplateAttr[file],max=TEMPLATE_LENGTH;
    //重复模板数据  到整个扇区 
    if(data.count("multiple")>0) {
        p=winhexTemplateAttr[file];
        for(int i=0;i<max;i+=len2) {
            memcpy(p+len2,p,len2);
        }
    }else{
        memset(p,0,max-len2);
    }
}

    string winhexTemplate_getNodes(){
        string rt;
        if(getWinsize("col")<90){            winhexTemplateNotes.clear();            return  rt;        }
    
        ostringstream in;  
        foreach(winhexTemplateNotes,it) {
            in << getColor(0,it->color,it->isB) << it->name<< ",";
        }
        winhexTemplateNotes.clear();
        in<<getColor();
        rt=in.str();
        return rt;
    }

void WinhexTemplate_dump(long pos=-1,long size=0x1FF) {
        if(pos==-1) pos=ds->postion;
        char *p=ds->get(pos);
        char *start=p;
        int i;
        char str[20];  
        memset(str,0,sizeof(str));
        if(size==0) size=1024;
        int line=1;
        printf("\n 0  1  2  3  4  5  6  7    8  9  A  B  C  D  E  F \n");
        for (i = 0; i <= size; i++) {
            if (i % 16 == 0 && i != 0)  { 
                printf("\t|%s|",str);
                cout << winhexTemplate_getNodes() << endl;
                str[0]='\0';
            }
            if (i % 16 == 8)  printf("  ");
            
            str[i%16]= isprint(p[0])?  p[0] :  '.' ;
            
            int pos=p-(char *) start;
            int color=winhexTemplateAttr[Template_Now][pos];
            
            //注释
           map<int,WINHEX_TEMPLATENOTE> node=winhexTemplateNodeName[Template_Now];
           if(color && node.count(pos)>0) {
               winhexTemplateNotes.push_back(node[pos]);
           }
           
            setColor(0,color,color?true:false);

            printf("%2.2x ", /* (unsigned int) p & 0xff*/(unsigned char)*p++);
            setColor();
        }
        
        printf("\t|%s|",str);
        cout << winhexTemplate_getNodes() << endl;
        return;
}

void WinHexTemplate_shell(){
    if(winhex_template_files.size()==0)
        winhex_template_files =listdir(WINHEX_TEMPLATE_DIR,".tpl");
    
    int i=1,n=winhex_template_files.size();
    if(n==0) {
        cout <<"没有找到模板文件@"<<  WINHEX_TEMPLATE_DIR <<endl;
        return;
    }
    printf("\n");
    foreach(winhex_template_files,it) {
        cout <<i++<<". "<< *it <<endl;
    }
    
    int index=0;
    char s[200];
    char c=getch(s);
    while(c==27) {
         switch(stoi(s)){
               case 279165:  //22 up
                   index--; break;
                case 279166:  //34 down
                    index++; break;
             default : 
                 break;
         }
         if(index<1) index=n; 
         else if(index>n) index=1;
         
         printf("\33[%dA",n);
         printf("\33[?25l");
         i=0;
        foreach(winhex_template_files,it){
            i++;
            if(i == index) setColor(2);
            cout <<i<<". "<< *it <<endl;
//            printf("\33[%dD\033[K%s\n",(int)it->size(),it->c_str());
            setColor(0);
         }
        c=getch(s);   
        if(c==10){
                 c=48+index; 
                 printf("\33[?25h"); //显示光标
        }
    }
    
    while(c< 48 || c>58-(10-n))     c=getch();
    
    WinhexTemplate_init(winhex_template_files.at(c-49));
    WinhexTemplate_dump();
}

    #endif /* NTFS_H */
